<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>

                    <h4>定义函数</h4>
                    <div class="x-wiki-info"><span>3020次阅读</span></div>
                    <hr style="border-top-color:#ccc" />
                    <div class="x-wiki-content x-content"><p>在Python中，定义一个函数要使用<code>def</code>语句，依次写出函数名、括号、括号中的参数和冒号<code>:</code>，然后，在缩进块中编写函数体，函数的返回值用<code>return</code>语句返回。</p>
<p>我们以自定义一个求绝对值的<code>my_abs</code>函数为例：</p>
<pre><code>def my_abs(x):
    if x &gt;= 0:
        return x
    else:
        return -x
</code></pre><p>请自行测试并调用<code>my_abs</code>看看返回结果是否正确。</p>
<p>请注意，函数体内部的语句在执行时，一旦执行到<code>return</code>时，函数就执行完毕，并将结果返回。因此，函数内部通过条件判断和循环可以实现非常复杂的逻辑。</p>
<p>如果没有<code>return</code>语句，函数执行完毕后也会返回结果，只是结果为<code>None</code>。</p>
<p><code>return None</code>可以简写为<code>return</code>。</p>
<h3 id="-">空函数</h3>
<p>如果想定义一个什么事也不做的空函数，可以用<code>pass</code>语句：</p>
<pre><code>def nop():
    pass
</code></pre><p><code>pass</code>语句什么都不做，那有什么用？实际上<code>pass</code>可以用来作为占位符，比如现在还没想好怎么写函数的代码，就可以先放一个<code>pass</code>，让代码能运行起来。</p>
<p><code>pass</code>还可以用在其他语句里，比如：</p>
<pre><code>if age &gt;= 18:
    pass
</code></pre><p>缺少了<code>pass</code>，代码运行就会有语法错误。</p>
<h3 id="-">参数检查</h3>
<p>调用函数时，如果参数个数不对，Python解释器会自动检查出来，并抛出<code>TypeError</code>：</p>
<pre><code>&gt;&gt;&gt; my_abs(1, 2)
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
TypeError: my_abs() takes exactly 1 argument (2 given)
</code></pre><p>但是如果参数类型不对，Python解释器就无法帮我们检查。试试<code>my_abs</code>和内置函数<code>abs</code>的差别：</p>
<pre><code>&gt;&gt;&gt; my_abs(&#39;A&#39;)
&#39;A&#39;
&gt;&gt;&gt; abs(&#39;A&#39;)
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
TypeError: bad operand type for abs(): &#39;str&#39;
</code></pre><p>当传入了不恰当的参数时，内置函数<code>abs</code>会检查出参数错误，而我们定义的<code>my_abs</code>没有参数检查，所以，这个函数定义不够完善。</p>
<p>让我们修改一下<code>my_abs</code>的定义，对参数类型做检查，只允许整数和浮点数类型的参数。数据类型检查可以用内置函数<code>isinstance</code>实现：</p>
<pre><code>def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError(&#39;bad operand type&#39;)
    if x &gt;= 0:
        return x
    else:
        return -x
</code></pre><p>添加了参数检查后，如果传入错误的参数类型，函数就可以抛出一个错误：</p>
<pre><code>&gt;&gt;&gt; my_abs(&#39;A&#39;)
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  File &quot;&lt;stdin&gt;&quot;, line 3, in my_abs
TypeError: bad operand type
</code></pre><p>错误和异常处理将在后续讲到。</p>
<h3 id="-">返回多个值</h3>
<p>函数可以返回多个值吗？答案是肯定的。</p>
<p>比如在游戏中经常需要从一个点移动到另一个点，给出坐标、位移和角度，就可以计算出新的新的坐标：</p>
<pre><code>import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny
</code></pre><p>这样我们就可以同时获得返回值：</p>
<pre><code>&gt;&gt;&gt; x, y = move(100, 100, 60, math.pi / 6)
&gt;&gt;&gt; print x, y
151.961524227 70.0
</code></pre><p>但其实这只是一种假象，Python函数返回的仍然是单一值：</p>
<pre><code>&gt;&gt;&gt; r = move(100, 100, 60, math.pi / 6)
&gt;&gt;&gt; print r
(151.96152422706632, 70.0)
</code></pre><p>原来返回值是一个tuple！但是，在语法上，返回一个tuple可以省略括号，而多个变量可以同时接收一个tuple，按位置赋给对应的值，所以，Python的函数返回多值其实就是返回一个tuple，但写起来更方便。</p>
<h3 id="-">小结</h3>
<p>定义函数时，需要确定函数名和参数个数；</p>
<p>如果有必要，可以先对参数的数据类型做检查；</p>
<p>函数体内部可以用<code>return</code>随时返回函数结果；</p>
<p>函数执行完毕也没有<code>return</code>语句时，自动<code>return None</code>。</p>
<p>函数可以同时返回多个值，但其实就是一个tuple。</p>
</div>

                    <hr style="border-top-color:#ccc" />

                    